from sqlalchemy.orm import Session
from sqlalchemy import desc, asc, func, and_, or_
from typing import List, Optional, Dict, Any, Tuple
from datetime import datetime, timedelta
import json
import uuid

from database import SchedulingStrategy
from schemas import (
    SchedulingStrategyCreate, 
    SchedulingStrategyUpdate, 
    SchedulingStrategyResponse,
    SchedulingStrategyConfig,
    SchedulingStrategyMetrics,
    PaginationParams
)
from exceptions import NotFoundException, ValidationException, BaseCustomException


class SchedulingService:
    """调度策略服务类"""
    
    def __init__(self, db: Session):
        self.db = db
    
    def create_strategy(self, strategy_data: SchedulingStrategyCreate) -> SchedulingStrategyResponse:
        """创建新的调度策略"""
        try:
            # 生成唯一的策略ID
            strategy_id = str(uuid.uuid4())
            
            # 准备配置数据
            config_json = None
            if strategy_data.config:
                config_json = json.dumps(strategy_data.config.model_dump())
            
            # 准备性能指标数据
            metrics_json = None
            if strategy_data.metrics:
                metrics_json = json.dumps(strategy_data.metrics.model_dump())
            
            # 创建数据库记录
            db_strategy = SchedulingStrategy(
                strategy_id=strategy_id,
                name=strategy_data.name,
                description=strategy_data.description,
                type=strategy_data.type,
                scenario=strategy_data.scenario,
                status=strategy_data.status,
                priority=strategy_data.priority,
                max_concurrent_tasks=strategy_data.max_concurrent_tasks,
                cloud_nodes=strategy_data.cloud_nodes,
                edge_nodes=strategy_data.edge_nodes,
                config=config_json,
                metrics=metrics_json,
                last_executed=strategy_data.last_executed,
                next_execution=strategy_data.next_execution
            )
            
            self.db.add(db_strategy)
            self.db.commit()
            self.db.refresh(db_strategy)
            
            return self._convert_to_response(db_strategy)
            
        except Exception as e:
            self.db.rollback()
            raise BaseCustomException(f"创建调度策略失败: {str(e)}")
    
    def get_strategy_by_id(self, strategy_id: str) -> SchedulingStrategyResponse:
        """根据ID获取调度策略"""
        db_strategy = self.db.query(SchedulingStrategy).filter(
            SchedulingStrategy.strategy_id == strategy_id
        ).first()
        
        if not db_strategy:
            raise NotFoundException(f"调度策略 {strategy_id} 不存在")
        
        return self._convert_to_response(db_strategy)
    def get_strategies(
        self,
        page: int = 1,
        page_size: int = 20,
        status_filter: Optional[str] = None,
        type_filter: Optional[str] = None,
        scenario_filter: Optional[str] = None,
        search_term: Optional[str] = None,
        sort_by: str = "created_at",
        sort_order: str = "desc"
    ) -> Tuple[List[SchedulingStrategyResponse], int]:
        """获取调度策略列表"""
        try:
            query = self.db.query(SchedulingStrategy)
            
            # 应用过滤条件
            if status_filter:
                query = query.filter(SchedulingStrategy.status == status_filter)
            
            if type_filter:
                query = query.filter(SchedulingStrategy.type == type_filter)
            
            if scenario_filter:
                query = query.filter(SchedulingStrategy.scenario == scenario_filter)
            
            if search_term:
                search_pattern = f"%{search_term}%"
                query = query.filter(
                    or_(
                        SchedulingStrategy.name.like(search_pattern),
                        SchedulingStrategy.description.like(search_pattern),
                        SchedulingStrategy.scenario.like(search_pattern)
                    )
                )
            
            # 获取总数
            total_count = query.count()
            
            # 应用排序
            if sort_order.lower() == "desc":
                query = query.order_by(desc(getattr(SchedulingStrategy, sort_by, SchedulingStrategy.created_at)))
            else:
                query = query.order_by(asc(getattr(SchedulingStrategy, sort_by, SchedulingStrategy.created_at)))
            
            # 应用分页
            offset = (page - 1) * page_size
            query = query.offset(offset).limit(page_size)
            
            db_strategies = query.all()
            
            # 转换为响应模型
            strategies = [self._convert_to_response(strategy) for strategy in db_strategies]
            
            return strategies, total_count
            
        except Exception as e:
            raise BaseCustomException(f"获取调度策略列表失败: {str(e)}")
    
    def update_strategy(self, strategy_id: str, update_data: SchedulingStrategyUpdate) -> SchedulingStrategyResponse:
        """更新调度策略"""
        try:
            db_strategy = self.db.query(SchedulingStrategy).filter(
                SchedulingStrategy.strategy_id == strategy_id
            ).first()
            
            if not db_strategy:
                raise NotFoundException(f"调度策略 {strategy_id} 不存在")
            
            # 更新字段
            update_dict = update_data.model_dump(exclude_unset=True)
            
            for field, value in update_dict.items():
                if field in ['config', 'metrics'] and value is not None:
                    # 特殊处理JSON字段
                    if isinstance(value, (SchedulingStrategyConfig, SchedulingStrategyMetrics)):
                        setattr(db_strategy, field, json.dumps(value.model_dump()))
                    else:
                        setattr(db_strategy, field, json.dumps(value))
                elif hasattr(db_strategy, field) and value is not None:
                    setattr(db_strategy, field, value)
            
            db_strategy.updated_at = datetime.utcnow()
            
            self.db.commit()
            self.db.refresh(db_strategy)
            
            return self._convert_to_response(db_strategy)
            
        except NotFoundException:
            raise
        except Exception as e:
            self.db.rollback()
            raise BaseCustomException(f"更新调度策略失败: {str(e)}")
    
    def delete_strategy(self, strategy_id: str) -> bool:
        """删除调度策略"""
        try:
            db_strategy = self.db.query(SchedulingStrategy).filter(
                SchedulingStrategy.strategy_id == strategy_id
            ).first()
            
            if not db_strategy:
                raise NotFoundException(f"调度策略 {strategy_id} 不存在")
            
            self.db.delete(db_strategy)
            self.db.commit()
            
            return True
            
        except NotFoundException:
            raise
        except Exception as e:
            self.db.rollback()
            raise BaseCustomException(f"删除调度策略失败: {str(e)}")
    
    def execute_strategy(self, strategy_id: str) -> Dict[str, Any]:
        """执行调度策略"""
        try:
            db_strategy = self.db.query(SchedulingStrategy).filter(
                SchedulingStrategy.strategy_id == strategy_id
            ).first()
            
            if not db_strategy:
                raise NotFoundException(f"调度策略 {strategy_id} 不存在")
            
            if db_strategy.status != "active":
                raise ValidationException(f"调度策略 {strategy_id} 状态不是active，无法执行")
            
            # 更新执行时间
            db_strategy.last_executed = datetime.utcnow()
            
            # 更新性能指标
            if db_strategy.metrics:
                try:
                    metrics = json.loads(db_strategy.metrics)
                    metrics["totalExecutions"] = metrics.get("totalExecutions", 0) + 1
                    db_strategy.metrics = json.dumps(metrics)
                except json.JSONDecodeError:
                    pass
            
            self.db.commit()
            
            # 这里可以添加实际的调度逻辑
            execution_result = {
                "strategy_id": strategy_id,
                "execution_time": datetime.utcnow().isoformat(),
                "status": "success",
                "message": "策略执行成功"
            }
            
            return execution_result
            
        except (NotFoundException, ValidationException):
            raise
        except Exception as e:
            self.db.rollback()
            raise BaseCustomException(f"执行调度策略失败: {str(e)}")
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取调度策略统计信息的简化版本，用于列表页面"""
        return self.get_strategy_statistics()
    
    def get_strategy_statistics(self) -> Dict[str, Any]:
        """获取调度策略统计信息"""
        try:
            total_count = self.db.query(SchedulingStrategy).count()
            active_count = self.db.query(SchedulingStrategy).filter(SchedulingStrategy.status == "active").count()
            draft_count = self.db.query(SchedulingStrategy).filter(SchedulingStrategy.status == "draft").count()
            paused_count = self.db.query(SchedulingStrategy).filter(SchedulingStrategy.status == "paused").count()
            deprecated_count = self.db.query(SchedulingStrategy).filter(SchedulingStrategy.status == "deprecated").count()
            
            # 按类型统计
            type_stats = self.db.query(
                SchedulingStrategy.type, 
                func.count(SchedulingStrategy.id)
            ).group_by(SchedulingStrategy.type).all()
            
            # 按场景统计
            scenario_stats = self.db.query(
                SchedulingStrategy.scenario, 
                func.count(SchedulingStrategy.id)
            ).group_by(SchedulingStrategy.scenario).all()
            
            return {
                "total": total_count,
                "by_status": {
                    "active": active_count,
                    "draft": draft_count,
                    "paused": paused_count,
                    "deprecated": deprecated_count
                },
                "by_type": {type_name: count for type_name, count in type_stats},
                "by_scenario": {scenario: count for scenario, count in scenario_stats}
            }
            
        except Exception as e:
            raise BaseCustomException(f"获取调度策略统计信息失败: {str(e)}")
    
    def _convert_to_response(self, db_strategy: SchedulingStrategy) -> SchedulingStrategyResponse:
        """将数据库对象转换为响应模型"""
        # 构建响应数据
        response_data = {
            "id": str(db_strategy.id),
            "strategy_id": db_strategy.strategy_id,
            "name": db_strategy.name,
            "description": db_strategy.description,
            "type": db_strategy.type,
            "scenario": db_strategy.scenario,
            "status": db_strategy.status,
            "priority": db_strategy.priority,
            "max_concurrent_tasks": db_strategy.max_concurrent_tasks,
            "cloud_nodes": db_strategy.cloud_nodes,
            "edge_nodes": db_strategy.edge_nodes,
            "last_executed": db_strategy.last_executed,
            "next_execution": db_strategy.next_execution,
            "created_at": db_strategy.created_at,
            "updated_at": db_strategy.updated_at
        }
        
        # 解析config字段
        if db_strategy.config:
            try:
                config_data = json.loads(db_strategy.config)
                response_data["config"] = SchedulingStrategyConfig(**config_data)
            except (json.JSONDecodeError, TypeError):
                response_data["config"] = None
        
        # 解析metrics字段
        if db_strategy.metrics:
            try:
                metrics_data = json.loads(db_strategy.metrics)
                response_data["metrics"] = SchedulingStrategyMetrics(**metrics_data)
            except (json.JSONDecodeError, TypeError):
                response_data["metrics"] = None
        
        return SchedulingStrategyResponse(**response_data)
    
    def initialize_strategies_from_config(self, db: Session) -> int:
        """从配置文件初始化调度策略数据"""
        try:
            from config import config
            
            # 检查是否启用自动初始化
            if not hasattr(config, 'scheduling_strategies') or not config.scheduling_strategies.get('enable_auto_init', False):
                return 0
            
            # 检查数据库中是否已有调度策略数据
            existing_count = db.query(SchedulingStrategy).count()
            if existing_count > 0:
                return 0  # 已有数据，跳过初始化
            
            strategies_config = config.scheduling_strategies.get('strategies', [])
            if not strategies_config:
                return 0
            
            created_count = 0
            
            for strategy_config in strategies_config:
                try:
                    # 解析时间字段
                    created_at = None
                    if strategy_config.get('created_at'):
                        created_at = datetime.strptime(strategy_config['created_at'], '%Y-%m-%d %H:%M:%S')
                    
                    last_executed = None
                    if strategy_config.get('last_executed'):
                        last_executed = datetime.strptime(strategy_config['last_executed'], '%Y-%m-%d %H:%M:%S')
                    
                    next_execution = None
                    if strategy_config.get('next_execution'):
                        next_execution = datetime.strptime(strategy_config['next_execution'], '%Y-%m-%d %H:%M:%S')
                    
                    # 准备配置数据
                    config_json = None
                    if strategy_config.get('config'):
                        config_json = json.dumps(strategy_config['config'])
                    
                    # 准备性能指标数据
                    metrics_json = None
                    if strategy_config.get('metrics'):
                        metrics_json = json.dumps(strategy_config['metrics'])
                    
                    # 创建数据库记录
                    db_strategy = SchedulingStrategy(
                        strategy_id=strategy_config['strategy_id'],
                        name=strategy_config['name'],
                        description=strategy_config['description'],
                        type=strategy_config['type'],
                        scenario=strategy_config['scenario'],
                        status=strategy_config.get('status', 'draft'),
                        priority=strategy_config.get('priority', 1),
                        max_concurrent_tasks=strategy_config.get('max_concurrent_tasks', 1),
                        cloud_nodes=strategy_config.get('cloud_nodes', 0),
                        edge_nodes=strategy_config.get('edge_nodes', 0),
                        config=config_json,
                        metrics=metrics_json,
                        created_at=created_at or datetime.utcnow(),
                        last_executed=last_executed,
                        next_execution=next_execution
                    )
                    
                    db.add(db_strategy)
                    created_count += 1
                    
                except Exception as e:
                    # 记录单个策略初始化失败，但继续处理其他策略
                    print(f"初始化调度策略失败 {strategy_config.get('strategy_id', 'unknown')}: {str(e)}")
                    continue
            
            if created_count > 0:
                db.commit()
            
            return created_count
            
        except Exception as e:
            db.rollback()
            raise BaseCustomException(f"从配置初始化调度策略失败: {str(e)}") 